/*
 * $AIST_Release: 0.9.0 $
 * Copyright 2011 Information Technology Research Institute, National
 * Institute of Advanced Industrial Science and Technology
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *    http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package parser.analyzer

import scala.util.parsing.input.Reader
import com.google.protobuf.Descriptors._
import data.Functions
import parser.Parser
import parser.Nodes._
import parser.DataTypes._
import parser.Results
import parser.Results._
import parser.analyzer.{TableSerializationInfoMaker => TSIM}

/**
 * Source code analyzer.
 */
object Analyzer {

  /**
   * Results of analysis.
   * 
   * @param ast      Analyzed syntax tree.
   * @param fds      ProtocolBuffers FileDescriptors
   */
  case class State(ast: List[Stmt], 
                   typeMap: Map[Int, DataType], 
                   fds: List[FileDescriptor], 
                   anonymousMap: Map[DataType, Descriptor])

  /**
   * Parses and analyzes Sawzall Clone code.
   */
  def parse(reader: Reader[Char]): Result[State] = {
    Parser.parse(reader) match {
      case Parser.Success(r, _) =>
        val globals = List(("input", BytesType)) ++ Functions.funcTableForAnalysis
        Analyzer.analyze(globals, r)

      case ns: Parser.NoSuccess =>
        failure(ns.next.pos, ns.msg)
    }
  }

  /**
   * Analyzes Sawzall Clone code.
   */
  def analyze(globals: Iterable[(String, DataType)], root: List[Stmt]): Result[State] = {
    for {
      ReadProto.State(pbFiles, pos)     <- ReadProto.read(root)
      TypeAnalyzer.State(ast, typeMap)  <- TypeAnalyzer.analyze(root, pbFiles, pos)
      TSIM.State(ast, fd, anonymousMap) <- TSIM.generate(ast, typeMap)
      MainAnalyzer.State(ast)           <- MainAnalyzer.analyze(ast, typeMap, globals)
    } yield State(ast, typeMap, pbFiles :+ fd, anonymousMap)
  }
}
